# Replication Code for Tables 1 and 2
# James M. Curry and Leah Rosenstiel
# Last Updated 12/3/2025


rm(list=ls())
library(tidyverse)
source("functions.R")



########## Unorthodox vs Orthodox Lawmaking (Table 2) ########## 

## Read in grants data
grants <- read_csv("grants.csv")


## Create variables needed for analysis
grants <- grants %>%
  mutate(lag_control = 1 - on_commit, #units are only included if they switch on to committee
         state_program = paste(state_abbr, program),
         year_cong = paste(year, congress),
         log_grant = log(grant+1),
         prior_year = year - 1) %>%
  left_join(select(grants,program,state,prior_year=year,prior_grant=grant)) %>%
  unique


#### Impact of Conference ----
# Treated Units = switched onto committee and no conference
# Control Units = switched onto committee and had a conference

grants <- grants %>%
  mutate(unorthodox = ifelse(no_conference == 1, 1, 0),
         treated = on_commit * unorthodox, #treated units are unorthodox law and on committee
         control = on_commit * (1 - unorthodox)) #control units are regular law and on committee 

## Create lags and leads and calculate weights  
conference_data <- make_boot_data(treat_var = "treated",untreat_var = "control",
                                lag_control = "lag_control", time_var = "year", 
                                compare_var = "year_cong", 
                                unit_var= "state_program", d_var="log_grant", 
                                lead_yrs = 2,lag_yrs = 2, df = grants)

# Calculate change in grant amount (long difference)
conference_data <- conference_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)

# Bootstrap
conference_coefs <- matrix(NA, nrow=1000, ncol=3)
conference_data <- conference_data[order(conference_data$state_program, 
                                         conference_data$year), ]
all_state_programs <- unique(conference_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- conference_data[conference_data$state_program%in%boot_state_program,]
  conference_coefs[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  conference_coefs[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  conference_coefs[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

conference_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(conference_coefs, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(conference_coefs,2, quantile, 0.975),
            ci025=apply(conference_coefs,2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),
                     df=nrow(conference_data[conference_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(conference_data[conference_data$obs_weight!=0,])
# Number of treated observations
nrow(conference_data[conference_data$obs_weight>0,])
# Number of control observations
nrow(conference_data[conference_data$obs_weight<0,])


#### Impact of No Senate Committee Report ----
# Treated Units = switched onto committee and was not reported
# Control Units = switched onto committee and was reported

grants <- grants %>%
  mutate(unorthodox = ifelse(s_nocommreport == 1, 1, 0),
         treated = on_commit * unorthodox, #treated units are unorthodox law and on committee
         control = on_commit * (1 - unorthodox)) #control units are regular law and on committee 

## Create lags and leads and calculate weights  
report_data <- make_boot_data(treat_var = "treated",untreat_var = "control",
                                  lag_control = "lag_control", time_var = "year", 
                                  compare_var = "year_cong", 
                                  unit_var= "state_program", d_var="log_grant", 
                                  lead_yrs = 2,lag_yrs = 2, df = grants)


# Calculate change in grant amount (long difference)
report_data <- report_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)

# Bootstrap
report_coefs <- matrix(NA, nrow=1000, ncol=3)
report_data <- report_data[order(report_data$state_program, 
                                         report_data$year), ]
all_state_programs <- unique(report_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- report_data[report_data$state_program%in%boot_state_program,]
  report_coefs[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  report_coefs[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  report_coefs[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

report_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(report_coefs, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(report_coefs,2, quantile, 0.975),
            ci025=apply(report_coefs,2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),
                     df=nrow(report_data[report_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(report_data[report_data$obs_weight!=0,])
# treated
nrow(report_data[report_data$obs_weight>0,])
#control
nrow(report_data[report_data$obs_weight<0,])


#### Composite Unorthodox ----
# Treated Units = switched onto committee and unorthodox reauth
# Control Units = switched onto committee and regular reauth
# Unorthodox = didn't have committee report and/or conference and/or post-committee adjustment

grants <- grants %>%
  mutate(unorthodox = ifelse(s_nocommreport + no_conference > 0, 1, 0),
         treated = on_commit * unorthodox, #treated units are unorthdox law and on committee
         control = on_commit * (1 - unorthodox)) #control units are regular law and on committee 

## Create lags and leads and calculate weights  
unorthodox_data <- make_boot_data(treat_var = "treated",untreat_var = "control",
                              lag_control = "lag_control", time_var = "year", 
                              compare_var = "year_cong", 
                              unit_var= "state_program", d_var="log_grant", 
                              lead_yrs = 2,lag_yrs = 2, df = grants)

# Calculate change in grant amount (long difference)
unorthodox_data <- unorthodox_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)

# Bootstrap
unorthodox_coefs <- matrix(NA, nrow=1000, ncol=3)
unorthodox_data <- unorthodox_data[order(unorthodox_data$state_program, 
                                         unorthodox_data$year), ]
all_state_programs <- unique(unorthodox_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- unorthodox_data[unorthodox_data$state_program%in%boot_state_program,]
  unorthodox_coefs[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  unorthodox_coefs[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  unorthodox_coefs[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

unorthodox_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(unorthodox_coefs, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(unorthodox_coefs,2, quantile, 0.975),
            ci025=apply(unorthodox_coefs,2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),
                     df=nrow(unorthodox_data[unorthodox_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(unorthodox_data[unorthodox_data$obs_weight!=0,])
# treated
nrow(unorthodox_data[unorthodox_data$obs_weight>0,])
#control
nrow(unorthodox_data[unorthodox_data$obs_weight<0,])




###### Is there a committee benefit? (Table 1) ######
# Treated Units = switched onto committee and reauthorized
# Control Units = switched onto committee and have yet to reauthorize
# Match based on state & committee
# reason to match this way is then you only look at states represented by
# committee members to mirror the previous analysis

# Read in the data again
grants <- read_csv("grants.csv")

#### Overall Committee Advantage ####

# Create new treated and control variables
committee_grants <- grants %>%
  filter(!is.na(on_commit) & !is.na(on_commit_prior) & !is.na(grant)) %>%
  mutate(treated = on_commit,
         control = 1 - on_commit,
         state_year = paste0(state_abbr,year),
         state_year_agency = paste0(state_abbr,year,agency),
         state_year_commit = paste0(state_abbr,year,committee_code),
         state_program = paste0(state_abbr, program),
         commit_year = paste(committee_code, year),
         program_year = paste(program, year),
         log_grant = log(grant+1),
         prior_year = year - 1) 

## Create lags and leads and calculate weights  
## Note: compare_var is also different from above analysis
commit_analysis_data <- make_boot_data(treat_var = "treated",
                                       untreat_var = "control",
                                       time_var = "year", 
                                       lag_control = "control",
                                       compare_var = "state_year_commit", 
                                       unit_var= "state_program", d_var="log_grant", 
                                       lead_yrs = 2,lag_yrs = 2, df = committee_grants)

# Calculate change in grant amount (long difference)
commit_analysis_data <- commit_analysis_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)


# Bootstrap
commit_coefs <- matrix(NA, nrow=1000, ncol=3)
commit_analysis_data <- commit_analysis_data[order(commit_analysis_data$state_program, 
                                     commit_analysis_data$year), ]
all_state_programs <- unique(commit_analysis_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- commit_analysis_data[commit_analysis_data$state_program%in%boot_state_program,]
  commit_coefs[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

commit_analysis_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(commit_coefs, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(commit_coefs,2, quantile, 0.975),
            ci025=apply(commit_coefs,2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),df=nrow(commit_analysis_data[commit_analysis_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(commit_analysis_data[commit_analysis_data$obs_weight!=0,])
# treated
nrow(commit_analysis_data[commit_analysis_data$obs_weight>0,])
# control
nrow(commit_analysis_data[commit_analysis_data$obs_weight<0,])


###### Estimate separately for orthodox and unorthodox ######
## Regular Order
committee_grants <- grants %>%
  filter(!is.na(on_commit) & !is.na(on_commit_prior) & !is.na(grant)) %>%
  mutate(unorthodox = ifelse(s_nocommreport + no_conference > 0, 1, 0),
         treated = ifelse(on_commit==1 & unorthodox==0, 1, 0),
         control = 1 - on_commit,
         state_year = paste0(state_abbr,year),
         state_year_agency = paste0(state_abbr,year,agency),
         state_year_commit = paste0(state_abbr,year,committee_code),
         state_program = paste0(state_abbr, program),
         commit_year = paste(committee_code, year),
         program_year = paste(program, year),
         log_grant = log(grant+1),
         prior_year = year - 1) 

## Create lags and leads and calculate weights  
## Note: compare_var is also different from above analysis
orth_commit_analysis_data <- make_boot_data(treat_var = "treated",
                                            untreat_var = "control",
                                            time_var = "year", 
                                            lag_control = "control",
                                            compare_var = "state_year_commit", 
                                            unit_var= "state_program", d_var="log_grant", 
                                            lead_yrs = 2,lag_yrs = 2, 
                                            df = committee_grants)

# Calculate change in grant amount (long difference)
orth_commit_analysis_data <- orth_commit_analysis_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)


# Bootstrap
commit_coefs3 <- matrix(NA, nrow=1000, ncol=3)
orth_commit_analysis_data <- orth_commit_analysis_data[order(orth_commit_analysis_data$state_program, 
                                                             orth_commit_analysis_data$year), ]
all_state_programs <- unique(orth_commit_analysis_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- orth_commit_analysis_data[orth_commit_analysis_data$state_program%in%boot_state_program,]
  commit_coefs3[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs3[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs3[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

orth_commit_analysis_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(commit_coefs3, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(commit_coefs3, 2, quantile, 0.975),
            ci025=apply(commit_coefs3, 2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),df=nrow(orth_commit_analysis_data[orth_commit_analysis_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(orth_commit_analysis_data[orth_commit_analysis_data$obs_weight!=0,])
#treated
nrow(orth_commit_analysis_data[orth_commit_analysis_data$obs_weight>0,])
#control
nrow(orth_commit_analysis_data[orth_commit_analysis_data$obs_weight<0,])


##### Unorthodox #####
committee_grants <- grants %>%
  filter(!is.na(on_commit) & !is.na(on_commit_prior) & !is.na(grant)) %>%
  mutate(unorthodox = ifelse(s_nocommreport + no_conference > 0, 1, 0),
         treated = on_commit * unorthodox,
         control = 1 - on_commit,
         state_year = paste0(state_abbr,year),
         state_year_commit = paste0(state_abbr, year, committee_code),
         state_year_agency = paste0(state_abbr,year,agency),
         state_program = paste0(state_abbr, program),
         commit_year = paste(committee_code, year),
         program_year = paste(program, year),
         log_grant = log(grant+1),
         prior_year = year - 1) 

## Create lags and leads and calculate weights  
## Note: compare_var is also different from above analysis
unorth_commit_analysis_data <- make_boot_data(treat_var = "treated",
                                              untreat_var = "control",
                                              time_var = "year", 
                                              lag_control = "control",
                                              compare_var = "state_year_commit", 
                                              unit_var= "state_program", d_var="log_grant", 
                                              lead_yrs = 2,lag_yrs = 2, df = committee_grants)

# Calculate change in grant amount (long difference)
unorth_commit_analysis_data <- unorth_commit_analysis_data %>%
  mutate(grant_change = log_grant - log_grant_p1,
         grant_change_t1 = log_grant_t1 - log_grant_p1,
         grant_change_t2 = log_grant_t2 - log_grant_p1)


# Bootstrap
commit_coefs2 <- matrix(NA, nrow=1000, ncol=3)
unorth_commit_analysis_data <- unorth_commit_analysis_data[order(unorth_commit_analysis_data$state_program, 
                                                                 unorth_commit_analysis_data$year), ]
all_state_programs <- unique(unorth_commit_analysis_data$state_program) #this is what we sample from
set.seed(1965)
for (i in 1:1000){
  boot_state_program <- sample(all_state_programs, size=length(all_state_programs),
                               replace=T)
  data_sub <- unorth_commit_analysis_data[unorth_commit_analysis_data$state_program%in%boot_state_program,]
  commit_coefs2[i,1] <- sum(data_sub$grant_change * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs2[i,2] <- sum(data_sub$grant_change_t1 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
  commit_coefs2[i,3] <- sum(data_sub$grant_change_t2 * data_sub$obs_weight, na.rm=T) / 
    sum(data_sub$treated * data_sub$obs_weight, na.rm=T)
}

unorth_commit_analysis_data %>%
  select(starts_with("grant_change"),obs_weight,treated) %>%
  rename(grant_change_t = grant_change) %>%
  pivot_longer(cols = c(starts_with("grant_change")),
               names_to = "time", names_pattern="_(t.*)",
               values_to = "grant_change") %>%
  group_by(time) %>%
  summarise(estimate=sum(grant_change*obs_weight,na.rm=T)/
              sum(treated*obs_weight,na.rm=T)) %>%
  bind_cols(std_error=apply(commit_coefs2, 2, function(x) sqrt(sum((x - mean(x))^2)/999)),
            ci975=apply(commit_coefs2,2, quantile, 0.975),
            ci025=apply(commit_coefs2,2, quantile, 0.025)) %>%
  # for p-value calculation, use conservative estimate of degrees of freedom
  # rather than all observations use only non-zero weighted ones
  mutate(tstat=estimate/std_error,
         pvalue=2*pt(-abs(tstat),df=nrow(unorth_commit_analysis_data[unorth_commit_analysis_data$obs_weight!=0,])-1)) %>%
  print_estimates()
# Number of observations with  non-zero weight
nrow(unorth_commit_analysis_data[unorth_commit_analysis_data$obs_weight!=0,])
# treated
nrow(unorth_commit_analysis_data[unorth_commit_analysis_data$obs_weight>0,])
#control
nrow(unorth_commit_analysis_data[unorth_commit_analysis_data$obs_weight<0,])


